package com.geek.gkfgw.web.demo;

import com.geek.gkfgw.facade.abs.Response;
import com.geek.gkfgw.framework.cache.ehcache.DemoEhcache;
import com.geek.gkfgw.framework.cache.redis.RedisLocker;
import com.geek.gkfgw.integration.demo.DemoControllerFeignClient;
import com.geek.gkfgw.integration.demo.DemoFacadeClient;
import com.geek.gkfgw.util.json.JacksonUtils;
import com.geek.gkfgw.web.anno.TokenIgnore;
import com.geek.gkfgw.web.model.BaseResponse;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.validation.constraints.NotBlank;
import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

@RestController
@RequestMapping("demo")
public class DemoController {

    @Autowired
    private DemoFacadeClient demoFacadeClient;
    @Autowired
    private DemoEhcache demoEhcache;
    @Autowired
    private DemoControllerFeignClient demoControllerFeignClient;
    @Autowired
    private RedisLocker redisLocker;

    @Setter
    @Getter
    @ToString
    public static class Info implements Serializable {
        @NotBlank
        String name;
        @NotBlank
        String age;
        String threadSize;
        String taskSize;
        String loopSize;
    }

    @TokenIgnore
    @GetMapping("/hello/{id}")
    public Response hello(@PathVariable String id){
        String msg = "DemoController recv args: id=" + id + ", date="
                +new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSSSS").format(new Date());
        return BaseResponse.ok(msg);
    }

    @TokenIgnore
    @GetMapping("/hello2/{id}")
    public Response hello2(@PathVariable String id){
        String msg = "DemoController recv args: id=" + Integer.parseInt(id)/0 + ", date="
                +new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSSSS").format(new Date());
        return BaseResponse.ok(msg);
    }

    @TokenIgnore
    @PostMapping("/hello3")
    public Response hello3(@RequestBody Info info){
        String msg = "DemoController recv args: id=" + info.toString() + ", date="
                +new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSSSS").format(new Date());
        return BaseResponse.ok(msg);
    }

    @TokenIgnore
    @PostMapping("/ehcache")
    public Response ehcache(@RequestBody Info info) {
        return BaseResponse.ok(demoEhcache.getDemoInfo(Integer.parseInt(info.age)));
    }

    @TokenIgnore
    @PostMapping("/feign")
    public Response feign(@RequestBody Info info){
        String msg = "feign recv args: " + demoControllerFeignClient.echo(info.name) + ", date="
                +new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSSSS").format(new Date());
        return BaseResponse.ok(msg);
    }

    @TokenIgnore
    @PostMapping("/dubbo")
    public Response dubbo(@RequestBody Info info){
        String msg = "dubbo";
//        String msg = "dubbo recv args: " + demoFacadeClient.invoke(info.name) + ", date="
//                +new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSSSS").format(new Date());
        return BaseResponse.ok(msg);
    }

    @TokenIgnore
    @PostMapping("/redis")
    public Response redis(@RequestBody Info info) throws Exception{
        ExecutorService executorService = Executors.newCachedThreadPool();
        int loopSize = Integer.parseInt(info.loopSize);
        int taskSize = Integer.parseInt(info.taskSize);
        int threadSize = Integer.parseInt(info.threadSize);
        String redisValue = JacksonUtils.toJson(info) + JacksonUtils.toJson(info) + JacksonUtils.toJson(info) + JacksonUtils.toJson(info) + JacksonUtils.toJson(info) + JacksonUtils.toJson(info);
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                long prefix = System.currentTimeMillis();
                for (int i = 0; i < taskSize; i++) {
                    String lockKey = prefix + ":" + String.valueOf(i);
                    redisLocker.tryLock(lockKey, redisValue, 30 * 1000L);
                }
            }
        };

        long start = System.currentTimeMillis();
        List<Future> futureList = new ArrayList<>();
        for (int wheel = 0; wheel < loopSize; wheel++) {
            futureList.clear();

            for (int item = 0; item < threadSize; item++) {
                futureList.add(executorService.submit(runnable));
            }
            for (Future future : futureList) {
                future.get();
            }
        }
        long end = System.currentTimeMillis();

        String msg = "redis 耗时：" +  (end - start) / loopSize + " ms," +
                "任务数："+ threadSize * taskSize +", date="
                +new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSSSS").format(new Date());
        return BaseResponse.ok(msg);
    }
}